package BaseDBEntity;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


import Utils.Bean2MapUtil;
import Utils.Map2BeanUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.dao.BaseDao;
import springmvc.common.CriteriaExample;

import Utils.CommUtil;
import Utils.GenericUtil;

@Transactional
public class BaseService<T> {
	/*
	 * 
	 * 用于缓存
	 */
	private Class<T> entityClass;
	private T object;
	private TableDescription tableAnnotation;

	@Autowired
	public BaseDao baseDao;

	/* public abstract BaseDao getBaseDao(); */

	/* public abstract DbProperties getDbProperties(); */

	private DbProperties getDbProperties(Map<String, Object> map)
			throws InstantiationException, IllegalAccessException {

		if (map == null) {
			return getDbPropertiesByName();
		}

		DbProperties dbProperties = getDbPropertiesExt();

		List<String> list = dbProperties.getPrimaryKeyNames();
		for (int i = 0; i < list.size(); i++) {

			list.set(i, list.get(i).toUpperCase());
		}

		for (Map.Entry<String, Object> entry : map.entrySet()) {
			if (list.contains(entry.getKey().toUpperCase())) {

				list.set(list.indexOf(entry.getKey().toUpperCase()),
						entry.getKey());

			}

		}

		/*
		 * 将两个for循环改成一个，进行优化 for (int i = 0; i < list.size(); i++) { for
		 * (Map.Entry<String, Object> entry : map.entrySet()) { if
		 * (entry.getKey().toUpperCase() .equals(list.get(i).toUpperCase())) {
		 * 
		 * list.set(i, entry.getKey()); break; } }
		 * 
		 * }
		 */
		if(list.size()>0) {
			dbProperties.setPrimaryKeyNames(list);
		}
		return dbProperties;
	}

	/*
	 * 
	 * 子类扩展
	 */
	@SuppressWarnings("unchecked")
	public DbProperties getDbPropertiesByName() throws InstantiationException,
			IllegalAccessException {

		DbProperties dbProperties = new DbProperties();

		if (object == null) {
			object = (T) GenericUtil.getGenericParameterObject(this.getClass());
		}

		dbProperties.setTableName(object.getClass().getSimpleName());
		return dbProperties;
	}

	@SuppressWarnings("unchecked")
	private Object getObject() throws InstantiationException,
			IllegalAccessException {

		if (object != null) {
			return object;
		}

		if (entityClass == null) {
			Type type = this.getClass().getGenericSuperclass();
			Type type2 = (ParameterizedType) type;
			// 获取泛型实际类型参数 如<k,v> --> <Integer,String>这种类型 0 --> Integer
			Type trueType = ((ParameterizedType) type2)
					.getActualTypeArguments()[0];

			entityClass = (Class<T>) trueType;
		}
		object = entityClass.newInstance();
		return object;
	}

	/*
	 * 
	 * 留给子类做扩展
	 */
	public DbProperties getDbPropertiesExt() throws InstantiationException,
			IllegalAccessException

	{// getObject()

		if (tableAnnotation == null) {
			tableAnnotation = GenericUtil
					.getGenericParameterObject(this.getClass()).getClass()
					.getAnnotation(TableDescription.class);
		}
		if (tableAnnotation != null) {
			DbProperties db = new DbProperties();

			String strTableName = tableAnnotation.tableName();
			if (!StringUtils.isEmpty(strTableName)) {
				db.setTableName(strTableName);
			} else {
				db.setTableName(this.getClass().getSimpleName());
			}

			String[] strKeyNames = tableAnnotation.primaryKeyNames();

			if (strKeyNames != null && strKeyNames.length > 0) {
				List<String> list = Arrays.asList(strKeyNames);

				db.setPrimaryKeyNames(list);

			}

			String strorderBy = tableAnnotation.orderBy();
			if (!StringUtils.isEmpty(strorderBy)) {

				db.setOrderBy(strorderBy);

			}

			return db;
		}

		return null;
	}

	public int insert(T object) throws InstantiationException,
			IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		/* getBaseDao().insert(map, getDbProperties()); */

		// getBaseDao().insert(map, getDbProperties3(map));

		return baseDao.insert(map, getDbProperties(map));
	}

	public int insertSelective(T object) throws InstantiationException,
			IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		/* getBaseDao().insert(map, getDbProperties()); */

		// getBaseDao().insert(map, getDbProperties3(map));

		return baseDao.insertSelective(map, getDbProperties(map));
	}

	public int deleteByPrimaryKeys(T object) throws InstantiationException,
			IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		return baseDao.deleteByPrimaryKeys(map, getDbProperties(map));
	}

	public int deleteList(T object) throws InstantiationException,
			IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		return baseDao.deleteList(map, getDbProperties(map));
	}

	public int updateByPrimaryKeys(T object) throws InstantiationException,
			IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		return baseDao.updateByPrimaryKeys(map, getDbProperties(map));

		/* getBaseDao().updateByPrimaryKeys(map, getDbProperties()); */
	}

	public int updateByPrimaryKeysSelective(T object)
			throws InstantiationException, IllegalAccessException {
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);
		return baseDao.updateByPrimaryKeysSelective(map, getDbProperties(map));

		/* getBaseDao().updateByPrimaryKeys(map, getDbProperties()); */
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> T queryList(T object) throws IOException,
			InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		if (object == null)
			return selectAll();
		List<T> listObjects = new ArrayList<T>();
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);

		/* DbProperties dbProperties = getDbProperties(); */

		/*
		 * DbProperties dbProperties = getDbProperties2();
		 * 
		 * List<String> list = dbProperties.getPrimaryKeyNames(); for (int i =
		 * 0; i < list.size(); i++) { for (Map.Entry<String, Object> entry :
		 * map.entrySet()) { if (entry.getKey().toUpperCase()
		 * .equals(list.get(i).toUpperCase())) {
		 * 
		 * list.set(i, entry.getKey()); break; } }
		 * 
		 * } dbProperties.setPrimaryKeyNames(list);
		 */

		List<Map<String, Object>> listMaps = baseDao.queryList(map,
				getDbProperties(map));

		for (int i = 0; i < listMaps.size(); i++) {
			Object o = Map2BeanUtil.mapToObject(listMaps.get(i), object.getClass());
			if (o != null) {
				listObjects.add((T) o);
			}
		}
		return (T) listObjects;

	}

	@SuppressWarnings("unchecked")
	/* @Transactional(propagation=Propagation.NOT_SUPPORTED) */
	@Cacheable(value = "cacheTest", keyGenerator = "springCacheKeyGenerator")
	public <T> T selectAll() throws IOException, InstantiationException,
			IllegalAccessException, IllegalArgumentException, ParseException {

		List<T> listObjects = new ArrayList<T>();

		/*
		 * if (object == null) { object = (T)
		 * GenericUtil.getGenericParameterObject(this.getClass()); }
		 */

		/* DbProperties dbProperties = getDbProperties(); */

		/*
		 * DbProperties dbProperties = getDbProperties2();
		 * 
		 * List<String> list = dbProperties.getPrimaryKeyNames(); for (int i =
		 * 0; i < list.size(); i++) { for (Map.Entry<String, Object> entry :
		 * map.entrySet()) { if (entry.getKey().toUpperCase()
		 * .equals(list.get(i).toUpperCase())) {
		 * 
		 * list.set(i, entry.getKey()); break; } }
		 * 
		 * } dbProperties.setPrimaryKeyNames(list);
		 */

		List<Map<String, Object>> listMaps = baseDao
				.selectAll(getDbProperties(null));

		for (int i = 0; i < listMaps.size(); i++) {
			Object o = Map2BeanUtil.mapToObject(listMaps.get(i), getObject()
					.getClass());
			if (o != null) {
				listObjects.add((T) o);
			}
		}
		return (T) listObjects;

	}

	/* <T> List<T> selectByPrimaryKeysToList */
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> T selectByPrimaryKeysToList(T object) throws IOException,
			InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		List<T> listObjects = new ArrayList<T>();
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);

		/* DbProperties dbProperties = getDbProperties(); */

		/*
		 * DbProperties dbProperties = getDbProperties2();
		 * 
		 * List<String> list = dbProperties.getPrimaryKeyNames(); for (int i =
		 * 0; i < list.size(); i++) { for (Map.Entry<String, Object> entry :
		 * map.entrySet()) { if (entry.getKey().toUpperCase()
		 * .equals(list.get(i).toUpperCase())) {
		 * 
		 * list.set(i, entry.getKey()); break; } }
		 * 
		 * } dbProperties.setPrimaryKeyNames(list);
		 */

		List<Map<String, Object>> listMaps = baseDao.selectByPrimaryKeysToList(
				map, getDbProperties(map));

		for (int i = 0; i < listMaps.size(); i++) {
			Object o = Map2BeanUtil.mapToObject(listMaps.get(i), object.getClass());
			if (o != null) {
				listObjects.add((T) o);
			}
		}
		return (T) listObjects;

	}

	public <T> T selectByPrimaryKeysToOne(T object) throws IOException,
			InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		List<T> listObjects = new ArrayList<T>();
		Map<String, Object> map = Bean2MapUtil.objectToMap(object);

		/* DbProperties dbProperties = getDbProperties(); */

		/*
		 * DbProperties dbProperties = getDbProperties2();
		 * 
		 * List<String> list = dbProperties.getPrimaryKeyNames(); for (int i =
		 * 0; i < list.size(); i++) { for (Map.Entry<String, Object> entry :
		 * map.entrySet()) { if (entry.getKey().toUpperCase()
		 * .equals(list.get(i).toUpperCase())) {
		 * 
		 * list.set(i, entry.getKey()); break; } }
		 * 
		 * } dbProperties.setPrimaryKeyNames(list);
		 */

		Map<String, Object> oneMap = baseDao.selectByPrimaryKeysToOne(map,
				getDbProperties(map));

		Object o = Map2BeanUtil.mapToObject(oneMap, object.getClass());

		return (T) o;

	}

	@SuppressWarnings("unchecked")
	public <T> List<T> selectByCriteria(CriteriaExample criteriaList)
			throws IOException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		DbProperties dbProperties = getDbPropertiesByName();

		List<T> listObjects = new ArrayList<T>();

		List<Map<String, Object>> listMaps = baseDao.selectByCriteria(
				criteriaList, dbProperties);

		for (int i = 0; i < listMaps.size(); i++) {
			Object o = Map2BeanUtil.mapToObject(listMaps.get(i), object.getClass());
			if (o != null) {
				listObjects.add((T) o);
			}
		}
		return listObjects;

	}

	@SuppressWarnings("unchecked")
	public List<T> selectByCriteria2(CriteriaExample criteriaList)
			throws IOException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		DbProperties dbProperties = getDbPropertiesByName();

		List<T> listObjects = new ArrayList<T>();

		if (object == null) {
			object = (T) GenericUtil.getGenericParameterObject(this.getClass());
		}

		List<Map<String, Object>> listMaps = baseDao.selectByCriteria(
				criteriaList, dbProperties);

		for (int i = 0; i < listMaps.size(); i++) {
			Object o = Map2BeanUtil.mapToObject(listMaps.get(i), object.getClass());
			if (o != null) {
				listObjects.add((T) o);
			}
		}
		return listObjects;

	}

	public int updateByCriteria(T object, CriteriaExample criteriaList)
			throws IOException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		DbProperties dbProperties = getDbPropertiesByName();

		Map<String, Object> map = Bean2MapUtil.objectToMap(object);

		return baseDao.updateByCriteria(criteriaList, dbProperties, map);

	}

	public int deleteByCriteria(CriteriaExample criteriaList)
			throws IOException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, ParseException {

		DbProperties dbProperties = getDbPropertiesByName();

		return baseDao.deleteByCriteria(criteriaList, dbProperties);

	}

	public int getCount() throws InstantiationException, IllegalAccessException {
		return baseDao.getCount(getDbProperties(null));
	}

	public int getCountByCriteria(CriteriaExample criteriaList)
			throws InstantiationException, IllegalAccessException {
		return baseDao.getCountByCriteria(criteriaList, getDbProperties(null));
	}

	public int batchInsert(List list) throws InstantiationException,
			IllegalAccessException {
		List<Map<String, Object>> listMaps = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < list.size(); i++) {
			Map<String, Object> map = Bean2MapUtil.objectToMap(list.get(i));
			if (map != null)
				listMaps.add(map);
		}
		return baseDao.batchInsert(listMaps, getDbProperties(null));
	}

	public int batchUpdate(List list) throws InstantiationException,
			IllegalAccessException {
		List<Map<String, Object>> listMaps = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < list.size(); i++) {
			Map<String, Object> map = Bean2MapUtil.objectToMap(list.get(i));
			if (map != null)
				listMaps.add(map);
		}
		DbProperties dbProperties = getDbPropertiesByName();
		return baseDao.batchUpdate(listMaps, dbProperties);
	}
}
